package interview;


import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import utils.Log;

public class PrinterSeqV2 {

  private final AtomicInteger mCount = new AtomicInteger(1);
  final int mThreadNum;
  final int mMax;
  List<CountDownLatch> mCountDownLatchList;
  CountDownLatch mDone;

  public PrinterSeqV2(int nThread, int max) {
    mThreadNum = nThread;
    mMax = max;
    mCountDownLatchList = new CopyOnWriteArrayList<>();
    mDone = new CountDownLatch(mThreadNum);
    reset();
  }

  void reset() {
    mCountDownLatchList.clear();
    for (int i = 0; i < mThreadNum; i++) {
      mCountDownLatchList.add(new CountDownLatch(i));
    }
  }


  public void start() {
    for (int i = 0; i < mThreadNum; i++) {
      new Thread(new SeqTask(i), String.valueOf(i + 1)).start();
    }
  }

  class SeqTask implements Runnable {

    final int seq;
    final int last;
    final int first;

    public SeqTask(int seq) {
      this.seq = seq;
      last = mThreadNum - 1;
      first = 0;
    }

    @Override
    public void run() {
      while (work()) {
        //Log.vn("thread#" + Thread.currentThread().getName() + ", running:");
      }
    }

    boolean work() {
      try {
        mCountDownLatchList.get(seq).await();

        if (seq == first) {
          mDone = new CountDownLatch(mThreadNum);
        }

        Log.vn(
            "thread#" + Thread.currentThread().getName() + ", count:" + mCount.getAndIncrement());
        for (int i = seq + 1; i < mThreadNum; i++) {
          mCountDownLatchList.get(i).countDown();
        }

        if (seq == last) {
          reset();
        }
        Thread.sleep(200);
        mDone.countDown();
        mDone.await();

        return true;
      } catch (Throwable tr) {
        tr.printStackTrace();
      }

      return false;
    }
  }
}
